<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>API 测试页面</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            line-height: 1.6;
            margin: 20px;
            background-color: #f4f4f4;
            color: #333;
        }
        .container {
            max-width: 900px;
            margin: auto;
            background: #fff;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
        }
        h1, h2 {
            color: #0056b3;
        }
        .api-section {
            margin-bottom: 30px;
            padding: 15px;
            border: 1px solid #ddd;
            border-radius: 5px;
            background-color: #fafafa;
        }
        .api-section h3 {
            margin-top: 0;
            color: #333;
        }
        .api-section label {
            display: block;
            margin-bottom: 5px;
            font-weight: bold;
        }
        .api-section input[type="text"],
        .api-section input[type="password"],
        .api-section select,
        .api-section textarea {
            width: calc(100% - 22px);
            padding: 10px;
            margin-bottom: 10px;
            border: 1px solid #ccc;
            border-radius: 4px;
        }
        .api-section button {
            background-color: #007bff;
            color: white;
            padding: 10px 15px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 16px;
        }
        .api-section button:hover {
            background-color: #0056b3;
        }
        .response {
            background-color: #e9e9e9;
            padding: 10px;
            border-radius: 4px;
            font-family: monospace;
            white-space: pre-wrap;
            word-wrap: break-word;
            margin-top: 15px;
            border: 1px solid #ccc;
        }
        .token-info {
            background-color: #dff0d8;
            border: 1px solid #d6e9c6;
            color: #3c763d;
            padding: 10px;
            border-radius: 4px;
            margin-bottom: 20px;
        }
        .error {
            color: red;
            font-weight: bold;
        }
        .sse-section {
            margin-top: 30px;
            padding: 15px;
            border: 1px solid #ddd;
            border-radius: 5px;
            background-color: #fafafa;
        }
        .sse-log {
            background-color: #e9e9e9;
            padding: 10px;
            border-radius: 4px;
            font-family: monospace;
            white-space: pre-wrap;
            word-wrap: break-word;
            margin-top: 15px;
            height: 200px;
            overflow-y: scroll;
            border: 1px solid #ccc;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>API 测试页面</h1>

        <div class="token-info">
            <h3>认证信息</h3>
            <p><strong>Access Token:</strong> <span id="accessToken">无</span></p>
            <p><strong>Refresh Token:</strong> <span id="refreshToken">无</span></p>
            <button onclick="clearTokens()">清除 Token</button>
        </div>

        <hr>

        <div class="api-section">
            <h3>POST /register (用户注册)</h3>
            <label for="registerUserId">userId:</label>
            <input type="text" id="registerUserId" value="testuser">
            <label for="registerPassword">password:</label>
            <input type="password" id="registerPassword" value="testpass">
            <button onclick="register()">注册</button>
            <div class="response" id="registerResponse"></div>
        </div>

        <div class="api-section">
            <h3>POST /login (用户登录)</h3>
            <label for="loginUserId">userId:</label>
            <input type="text" id="loginUserId" value="testuser">
            <label for="loginPassword">password:</label>
            <input type="password" id="loginPassword" value="testpass">
            <button onclick="login()">登录</button>
            <div class="response" id="loginResponse"></div>
        </div>

        <div class="api-section">
            <h3>POST /refresh-jwt (刷新 Access Token)</h3>
            <label for="refreshJwtToken">refreshToken:</label>
            <input type="text" id="refreshJwtToken" placeholder="从登录或注册获取">
            <button onclick="refreshJwt()">刷新</button>
            <div class="response" id="refreshJwtResponse"></div>
        </div>

        <div class="api-section">
            <h3>POST /getAuthorizationCode (获取授权码)</h3>
            <label for="authCodeUserId">userId:</label>
            <input type="text" id="authCodeUserId" value="testuser">
            <label for="authCodeBrand">brand:</label>
            <select id="authCodeBrand">
                <option value="xiaomi">xiaomi</option>
                <option value="midea">midea</option>
            </select>
            <button onclick="getAuthorizationCode()">获取授权码</button>
            <div class="response" id="authCodeResponse"></div>
        </div>

        <div class="api-section">
            <h3>POST /code (绑定第三方账号)</h3>
            <label for="code">code:</label>
            <input type="text" id="code" value="mock_code_123">
            <label for="brand">brand:</label>
            <select id="brand">
                <option value="xiaomi">xiaomi</option>
                <option value="midea">midea</option>
            </select>
            <button onclick="bindThirdParty()">绑定</button>
            <div class="response" id="bindResponse"></div>
        </div>

        <div class="api-section">
            <h3>POST /unbind (解绑第三方账号)</h3>
            <label for="unbindBrand">brand:</label>
            <select id="unbindBrand">
                <option value="xiaomi">xiaomi</option>
                <option value="midea">midea</option>
            </select>
            <button onclick="unbindThirdParty()">解绑</button>
            <div class="response" id="unbindResponse"></div>
        </div>

        <div class="api-section">
            <h3>GET /bindings (绑定状态查询)</h3>
            <button onclick="getBindings()">查询绑定</button>
            <div class="response" id="bindingsResponse"></div>
        </div>

        <hr>

        <div class="api-section">
            <h3>GET /device/getList (获取设备列表)</h3>
            <button onclick="getDeviceList()">获取设备</button>
            <div class="response" id="deviceListResponse"></div>
        </div>

        <div class="api-section">
            <h3>POST /device/createGroup (创建分组)</h3>
            <label for="groupName">gname:</label>
            <input type="text" id="groupName" value="客厅">
            <button onclick="createGroup()">创建分组</button>
            <div class="response" id="createGroupResponse"></div>
        </div>

        <div class="api-section">
            <h3>POST /device/setGroup (设置设备分组)</h3>
            <label for="setGroupDeviceId">device_id:</label>
            <input type="text" id="setGroupDeviceId" placeholder="设备ID">
            <label for="setGroupGroupId">group_id (可选，为空则解绑):</label>
            <input type="text" id="setGroupGroupId" placeholder="分组ID">
            <button onclick="setDeviceGroup()">设置分组</button>
            <div class="response" id="setGroupResponse"></div>
        </div>

        <div class="api-section">
            <h3>POST /device/deleteGroup (删除分组)</h3>
            <label for="deleteGroupId">gid:</label>
            <input type="text" id="deleteGroupId" placeholder="分组ID">
            <button onclick="deleteGroup()">删除分组</button>
            <div class="response" id="deleteGroupResponse"></div>
        </div>

        <div class="api-section">
            <h3>GET /device/groups (获取分组列表)</h3>
            <button onclick="getGroups()">获取分组列表</button>
            <div class="response" id="getGroupsResponse"></div>
        </div>

        <div class="api-section">
            <h3>GET /device/status (获取全部设备状态)</h3>
            <button onclick="getDeviceStatus()">获取状态</button>
            <div class="response" id="deviceStatusResponse"></div>
        </div>

        <div class="api-section">
            <h3>POST /device/control (设备控制)</h3>
            <label for="controlDid">did:</label>
            <input type="text" id="controlDid" placeholder="设备ID">
            <label for="controlOperation">operation:</label>
            <input type="text" id="controlOperation" placeholder="例如: power">
            <label for="controlValue">value:</label>
            <input type="text" id="controlValue" placeholder="例如: ON, OFF, 25">
            <button onclick="controlDevice()">控制设备</button>
            <div class="response" id="controlResponse"></div>
        </div>

        <hr>

        <div class="api-section">
            <h3>GET /sensor-data/last24h (查询24小时传感器数据)</h3>
            <label for="sensorDeviceId">device_id:</label>
            <input type="text" id="sensorDeviceId" placeholder="设备ID">
            <label for="sensorMetricType">metric_type:</label>
            <input type="text" id="sensorMetricType" placeholder="例如: temperature, humidity, pm25">
            <button onclick="getSensorDataLast24h()">查询</button>
            <div class="response" id="sensorDataResponse"></div>
        </div>

        <hr>

        <h2>场景管理</h2>
        <div class="api-section">
            <h3>1. 新增场景 (POST /api/scenes)</h3>
            <form id="createSceneForm">
                <label for="createScene_sceneName">场景名称:</label>
                <input type="text" id="createScene_sceneName" value="我的新场景" required><br>
                <label for="createScene_gid">分组ID:</label>
                <input type="text" id="createScene_gid" value="你的分组ID" placeholder="例如：group-123" required><br>
                <label for="createScene_actions">动作列表 (JSON Array):</label>
                <textarea id="createScene_actions" rows="8" cols="50" placeholder="[{ did: '...', operation: '...', value: '...' }]" required>
[
    { "did": "your_device_id_1", "operation": "power", "value": true },
    { "did": "your_device_id_2", "operation": "brightness", "value": 50 }
]</textarea><br>
                <button type="submit">创建场景</button>
            </form>
            <div class="response" id="createSceneResponse"></div>
        </div>

        <div class="api-section">
            <h3>2. 获取所有场景简略信息 (GET /api/scenes)</h3>
            <button id="getAllScenesBtn">获取场景列表</button>
            <div class="response" id="getAllScenesResponse"></div>
        </div>

        <div class="api-section">
            <h3>3. 获取指定场景完整信息 (GET /api/scenes/:scene_id)</h3>
            <form id="getSceneByIdForm">
                <label for="getSceneById_sceneId">场景ID:</label>
                <input type="text" id="getSceneById_sceneId" placeholder="请输入场景ID" required><br>
                <button type="submit">获取场景详情</button>
            </form>
            <div class="response" id="getSceneByIdResponse"></div>
        </div>

        <div class="api-section">
            <h3>4. 更新场景动作 (PATCH /api/scenes/:scene_id)</h3>
            <form id="updateSceneActionsForm">
                <label for="updateScene_sceneId">场景ID:</label>
                <input type="text" id="updateScene_sceneId" placeholder="请输入要更新的场景ID" required><br>
                <label for="updateScene_actions">动作更新 (JSON Object: {"add": [], "remove": []}):</label>
                <textarea id="updateScene_actions" rows="10" cols="50" placeholder="例如：{"add": [{"did": "...", "operation": "...", "value": "..."}, ...], "remove": ["action_id_to_remove", ...]}" required>
{
    "add": [
        { "did": "your_new_device_id", "operation": "color", "value": "#FF0000" }
    ],
    "remove": [
        "your_action_id_to_remove"
    ]
}</textarea><br>
                <button type="submit">更新场景动作</button>
            </form>
            <div class="response" id="updateSceneActionsResponse"></div>
        </div>

        <div class="api-section">
            <h3>5. 执行场景 (POST /api/scenes/:scene_id/execute)</h3>
            <form id="executeSceneForm">
                <label for="executeScene_sceneId">场景ID:</label>
                <input type="text" id="executeScene_sceneId" placeholder="请输入要执行的场景ID" required><br>
                <button type="submit">执行场景</button>
            </form>
            <div class="response" id="executeSceneResponse"></div>
        </div>

        <div class="api-section">
            <h3>6. 删除指定场景 (DELETE /api/scenes/:scene_id)</h3>
            <form id="deleteSceneForm">
                <label for="deleteScene_sceneId">场景ID:</label>
                <input type="text" id="deleteScene_sceneId" placeholder="请输入要删除的场景ID" required><br>
                <button type="submit">删除场景</button>
            </form>
            <div class="response" id="deleteSceneResponse"></div>
        </div>

        <hr>

        <div class="api-section">
            <h2>第三方通知接口 (非客户端调用)</h2>
            <p>以下接口通常由第三方系统调用，用于推送设备状态更新，无需前端手动测试。</p>
            <h3>POST /api/midea/notify (美的通知)</h3>
            <label for="mideaApplianceCode">applianceCode:</label>
            <input type="text" id="mideaApplianceCode" value="midea_test_did">
            <label for="mideaProperties">properties (JSON):</label>
            <textarea id="mideaProperties">{ "power": "ON", "mode": "cool" }</textarea>
            <button onclick="sendMideaNotify()">发送美的通知</button>
            <div class="response" id="mideaNotifyResponse"></div>
        </div>

        <div class="api-section">
            <h3>POST /api/xiaomi/notify (小米通知)</h3>
            <label for="xiaomiDid">did:</label>
            <input type="text" id="xiaomiDid" value="xiaomi_test_did">
            <label for="xiaomiData">data (JSON):</label>
            <textarea id="xiaomiData">{ "temperature": 25, "humidity": 60 }</textarea>
            <button onclick="sendXiaomiNotify()">发送小米通知</button>
            <div class="response" id="xiaomiNotifyResponse"></div>
        </div>

        <hr>

        <div class="sse-section">
            <h2>SSE 实时推送</h2>
            <label for="sseConId">SSE Connection ID (您的 userId):</label>
            <input type="text" id="sseConId" value="testuser">
            <button onclick="startSse()">连接 SSE</button>
            <button onclick="stopSse()">断开 SSE</button>
            <button onclick="sendSseExit()">主动退出 SSE</button>
            <h4>SSE 日志:</h4>
            <div class="sse-log" id="sseLog"></div>
        </div>

    </div>

    <script>
        // API 基础 URL (根据您的实际部署修改)
        const BASE_URL = 'http://localhost:3000'; // 假设您的后端运行在 3000 端口

        let accessToken = localStorage.getItem('accessToken') || '';
        let refreshToken = localStorage.getItem('refreshToken') || '';
        let eventSource = null; // 用于存储 SSE EventSource 实例

        // 更新页面上显示的 Token
        function updateTokenDisplay() {
            document.getElementById('accessToken').textContent = accessToken || '无';
            document.getElementById('refreshToken').textContent = refreshToken || '无';
        }

        // 清除 Token
        function clearTokens() {
            accessToken = '';
            refreshToken = '';
            localStorage.removeItem('accessToken');
            localStorage.removeItem('refreshToken');
            updateTokenDisplay();
            alert('Tokens 已清除');
        }

        // // 通用 API 请求函数
        // async function callApi(method, path, body = null, requiresAuth = false) {
        //     const options = {
        //         method: method,
        //         headers: {
        //             'Content-Type': 'application/json',
        //         },
        //     };
        //
        //     if (requiresAuth && accessToken) {
        //         options.headers['Authorization'] = `Bearer ${accessToken}`;
        //     }
        //
        //     if (body) {
        //         options.body = JSON.stringify(body);
        //     }
        //
        //     try {
        //         const response = await fetch(`${BASE_URL}${path}`, options);
        //         const data = await response.json();
        //         return data;
        //     } catch (error) {
        //         console.error('API 请求失败:', error);
        //         return { status: 'error', message: 'API 请求失败，请检查网络或后端服务' };
        //     }
        // }

        // 通用 API 请求函数 (修改后)
        async function callApi(method, path, body = null, requiresAuth = false) {
            const options = {
                method: method,
                headers: {
                    'Content-Type': 'application/json',
                },
            };

            if (requiresAuth && accessToken) {
                options.headers['Authorization'] = `Bearer ${accessToken}`;
            }

            if (body) {
                options.body = JSON.stringify(body);
            }

            try {
                const response = await fetch(`${BASE_URL}${path}`, options);

                // --- 核心修改部分 ---
                // 检查响应状态码是否为 204 (No Content)
                if (response.status === 204) {
                    return {code: 204, message: 'No Content'}; // 返回一个表示成功的结构
                }

                // 如果不是 204，才尝试解析 JSON
                const data = await response.json();
                return data;
            } catch (error) {
                console.error('API 请求失败:', error);
                // 对于 network error 或 JSON parse error，返回统一错误格式
                return {code: 500, message: 'API 请求失败，请检查网络或后端服务'};
            }
        }



        // 统一处理 API 响应并更新 UI
        function handleApiResponse(response, elementId) {
            const responseDiv = document.getElementById(elementId);
            if (response.status === 'success' || response.code === 200) {
                responseDiv.innerHTML = `<pre>${JSON.stringify(response, null, 2)}</pre>`;
                responseDiv.style.backgroundColor = '#dff0d8';
                responseDiv.style.borderColor = '#d6e9c6';
                responseDiv.style.color = '#3c763d';
            } else {
                responseDiv.innerHTML = `<pre class="error">${JSON.stringify(response, null, 2)}</pre>`;
                responseDiv.style.backgroundColor = '#f2dede';
                responseDiv.style.borderColor = '#ebccd1';
                responseDiv.style.color = '#a94442';
            }
        }

        // 用户注册
        async function register() {
            const userId = document.getElementById('registerUserId').value;
            const password = document.getElementById('registerPassword').value;
            const response = await callApi('POST', '/auth/register', { userId, password });
            handleApiResponse(response, 'registerResponse');
        }

        // 用户登录
        async function login() {
            const userId = document.getElementById('loginUserId').value;
            const password = document.getElementById('loginPassword').value;
            const response = await callApi('POST', '/auth/login', { userId, password });
            handleApiResponse(response, 'loginResponse');
            if (response.status === 'success' && response.data) {
                accessToken = response.data.token;
                refreshToken = response.data.refreshToken;
                localStorage.setItem('accessToken', accessToken);
                localStorage.setItem('refreshToken', refreshToken);
                updateTokenDisplay();
                document.getElementById('refreshJwtToken').value = refreshToken; // 自动填充刷新 token
            }
        }

        // 刷新 Access Token
        async function refreshJwt() {
            const token = document.getElementById('refreshJwtToken').value;
            const response = await callApi('POST', '/auth/refresh-jwt', { refreshToken: token });
            handleApiResponse(response, 'refreshJwtResponse');
            if (response.status === 'success' && response.data) {
                accessToken = response.data.token;
                localStorage.setItem('accessToken', accessToken);
                updateTokenDisplay();
            }
        }

        // 获取授权码
        async function getAuthorizationCode() {
            const userId = document.getElementById('authCodeUserId').value;
            const brand = document.getElementById('authCodeBrand').value;
            const response = await callApi('POST', '/mockapi/auth/getAuthorizationCode', { userId, brand });
            handleApiResponse(response, 'authCodeResponse');
            // 可以选择将获取到的 authorizationCode 自动填充到 /code 接口的 code 字段，方便测试
            if (response.status === 'success' && response.data && response.data.authorizationCode) {
                document.getElementById('code').value = response.data.authorizationCode;
            }
        }

        // 绑定第三方账号
        async function bindThirdParty() {
            const code = document.getElementById('code').value;
            const brand = document.getElementById('brand').value;
            const response = await callApi('POST', '/auth/code', { code, brand }, true);
            handleApiResponse(response, 'bindResponse');
        }

        // 解绑第三方账号
        async function unbindThirdParty() {
            const brand = document.getElementById('unbindBrand').value;
            const response = await callApi('POST', '/auth/unbind', { brand }, true);
            handleApiResponse(response, 'unbindResponse');
        }

        // 绑定状态查询
        async function getBindings() {
            const response = await callApi('GET', '/auth/bindings', null, true);
            handleApiResponse(response, 'bindingsResponse');
        }

        // 获取设备列表
        async function getDeviceList() {
            const response = await callApi('GET', '/devices/getList', null, true);
            handleApiResponse(response, 'deviceListResponse');
        }

        // 创建分组
        async function createGroup() {
            const gname = document.getElementById('groupName').value;
            const response = await callApi('POST', '/devices/createGroup', { gname }, true);
            handleApiResponse(response, 'createGroupResponse');
        }

        // 设置设备分组
        async function setDeviceGroup() {
            const device_id = document.getElementById('setGroupDeviceId').value;
            let group_id = document.getElementById('setGroupGroupId').value;
            // 如果 group_id 为空字符串，则设为 null 以便解绑
            if (group_id === '') {
                group_id = null;
            }
            const response = await callApi('POST', '/devices/setGroup', { device_id, group_id }, true);
            handleApiResponse(response, 'setGroupResponse');
        }

        // 删除分组
        async function deleteGroup() {
            const gid = document.getElementById('deleteGroupId').value;
            const response = await callApi('POST', '/devices/deleteGroup', { gid }, true);
            handleApiResponse(response, 'deleteGroupResponse');
        }

        // 获取分组列表
        async function getGroups() {
            const response = await callApi('GET', '/devices/groups', null, true);
            handleApiResponse(response, 'getGroupsResponse');
        }

        // 获取全部设备状态
        async function getDeviceStatus() {
            const response = await callApi('GET', '/devices/status', null, true);
            handleApiResponse(response, 'deviceStatusResponse');
        }

        // 控制设备
        async function controlDevice() {
            const did = document.getElementById('controlDid').value;
            const operation = document.getElementById('controlOperation').value;
            const value = document.getElementById('controlValue').value;

            // 尝试将 value 转换为数字或布尔值
            let parsedValue = value;
            if (!isNaN(parseFloat(value)) && isFinite(value)) {
                parsedValue = parseFloat(value);
            } else if (value.toLowerCase() === 'true') {
                parsedValue = true;
            } else if (value.toLowerCase() === 'false') {
                parsedValue = false;
            }

            const response = await callApi('POST', '/devices/control', {
                did,
                control: { operation, value: parsedValue }
            }, true);
            handleApiResponse(response, 'controlResponse');
        }

        // 查询设备最近24小时某指标的传感器记录
        async function getSensorDataLast24h() {
            const device_id = document.getElementById('sensorDeviceId').value;
            const metric_type = document.getElementById('sensorMetricType').value;
            const response = await callApi('GET', `/api/sensor-data/last24h?device_id=${device_id}&metric_type=${metric_type}`, null, true);
            handleApiResponse(response, 'sensorDataResponse');
        }


        // 发送美的通知 (用于测试SSE推送)
        async function sendMideaNotify() {
            const applianceCode = document.getElementById('mideaApplianceCode').value;
            // const userId = document.getElementById('mideaUserId').value;
            const properties = JSON.parse(document.getElementById('mideaProperties').value);
            const response = await callApi('POST', '/api/midea/notify', { applianceCode,  properties });
            handleApiResponse(response, 'mideaNotifyResponse');
        }

        // 发送小米通知 (用于测试SSE推送)
        async function sendXiaomiNotify() {
            const did = document.getElementById('xiaomiDid').value;
            // const userId = document.getElementById('xiaomiUserId').value;
            const data = JSON.parse(document.getElementById('xiaomiData').value);
            const response = await callApi('POST', '/api/xiaomi/notify', { did,  data });
            handleApiResponse(response, 'xiaomiNotifyResponse');
        }

        // SSE 相关函数
        function logSseEvent(message) {
            const sseLog = document.getElementById('sseLog');
            const p = document.createElement('p');
            p.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
            sseLog.appendChild(p);
            sseLog.scrollTop = sseLog.scrollHeight; // 滚动到底部
        }

        function startSse() {
            const sseConId = document.getElementById('sseConId').value;
            if (!sseConId) {
                alert('请输入 SSE Connection ID (userId)');
                return;
            }

            if (eventSource) {
                alert('SSE 连接已存在，请先断开。');
                return;
            }

            logSseEvent(`尝试连接 SSE，userId: ${sseConId}...`);
            eventSource = new EventSource(`${BASE_URL}/events?sseconid=${sseConId}`);

            eventSource.onopen = (event) => {
                logSseEvent('SSE 连接已建立！');
            };

            eventSource.onmessage = (event) => {
                try {
                    const data = JSON.parse(event.data);
                    logSseEvent(`收到 SSE 消息: ${JSON.stringify(data, null, 2)}`);
                } catch (e) {
                    logSseEvent(`收到原始 SSE 消息: ${event.data}`);
                }
            };

            eventSource.onerror = (error) => {
                logSseEvent(`SSE 连接错误: ${error.message || error}`);
                eventSource.close();
                eventSource = null;
            };

            eventSource.onclose = () => {
                logSseEvent('SSE 连接已关闭。');
                eventSource = null;
            };
        }

        function stopSse() {
            if (eventSource) {
                eventSource.close();
                eventSource = null;
                logSseEvent('SSE 连接已手动断开。');
            } else {
                alert('没有活跃的 SSE 连接。');
            }
        }


        async function sendSseExit() {
            const sseConId = document.getElementById('sseConId').value;
            if (!sseConId) {
                alert('请输入 SSE Connection ID (userId)');
                return;
            }

            // 确保 callApi 调用时开启认证
            // 如果 /api/sse/exit 接口需要认证，这里必须设置为 true
            const response = await callApi('POST', '/api/sse/exit', {sseconid: sseConId}, true); // 将 requiresAuth 设置为 true

            // handleApiResponse 函数已经包含了对成功和失败的样式处理
            // 但是对于 SSE 退出这种特定逻辑，我们可以在这里做更细致的判断
            handleApiResponse(response, 'sseLog'); // 在日志区域显示原始API响应

            // 根据后端实际返回的成功/失败状态码进行判断
            // 假设后端成功会返回 { code: 200, message: "SSE connection closed" } 或者其他表示成功的JSON
            // 如果是204 No Content，response会是空对象，code和status可能不存在
            if (response && (response.code === 200 || response.status === 'success')) {
                logSseEvent('成功发送 SSE 退出请求，后端确认连接已关闭。');
                if (eventSource) {
                    eventSource.close(); // 主动关闭前端的EventSource连接
                    eventSource = null;
                    logSseEvent('前端 SSE 连接已断开。');
                }
            } else if (response && response.code === 204) { // 特殊处理204 No Content，通常表示成功但无返回体
                logSseEvent('成功发送 SSE 退出请求，后端返回 204 No Content (表示成功)。');
                if (eventSource) {
                    eventSource.close(); // 主动关闭前端的EventSource连接
                    eventSource = null;
                    logSseEvent('前端 SSE 连接已断开。');
                }
            } else {
                // 捕获 API 失败或非预期响应
                logSseEvent(`发送 SSE 退出请求失败: ${JSON.stringify(response)}`);
            }
        }

        // --- 场景管理 API 调用 ---
        // 注意：这里所有的 sendRequest 已经被上面的 callApi 统一替代。
        // 只需要更新事件监听器，使其调用 callApi 即可。

        // 1. 新增场景
        document.getElementById('createSceneForm').addEventListener('submit', async (e) => {
            e.preventDefault();
            const sceneName = document.getElementById('createScene_sceneName').value;
            const gid = document.getElementById('createScene_gid').value;
            const actionsStr = document.getElementById('createScene_actions').value;
            let actions;
            try {
                actions = JSON.parse(actionsStr);
            } catch (error) {
                document.getElementById('createSceneResponse').innerHTML = `<pre class="error">JSON 格式错误：${error.message}</pre>`;
                return;
            }

            const response = await callApi('POST', '/api/scenes', {
                scene_name: sceneName,
                gid: gid,
                actions: actions
            }, true); // 需要认证
            handleApiResponse(response, 'createSceneResponse');
        });

        // 2. 获取所有场景简略信息
        document.getElementById('getAllScenesBtn').addEventListener('click', async () => {
            const response = await callApi('GET', '/api/scenes', null, true); // 需要认证
            handleApiResponse(response, 'getAllScenesResponse');
        });

        // 3. 获取指定场景完整信息
        document.getElementById('getSceneByIdForm').addEventListener('submit', async (e) => {
            e.preventDefault();
            const sceneId = document.getElementById('getSceneById_sceneId').value;
            const response = await callApi('GET', `/api/scenes/${sceneId}`, null, true); // 需要认证
            handleApiResponse(response, 'getSceneByIdResponse');
        });

        // 4. 更新场景动作
        document.getElementById('updateSceneActionsForm').addEventListener('submit', async (e) => {
            e.preventDefault();
            const sceneId = document.getElementById('updateScene_sceneId').value;
            const actionsStr = document.getElementById('updateScene_actions').value;
            let actions;
            try {
                actions = JSON.parse(actionsStr);
            } catch (error) {
                document.getElementById('updateSceneActionsResponse').innerHTML = `<pre class="error">JSON 格式错误：${error.message}</pre>`;
                return;
            }

            const response = await callApi('PATCH', `/api/scenes/${sceneId}`, { actions }, true); // 需要认证
            handleApiResponse(response, 'updateSceneActionsResponse');
        });

        // 5. 执行场景
        document.getElementById('executeSceneForm').addEventListener('submit', async (e) => {
            e.preventDefault();
            const sceneId = document.getElementById('executeScene_sceneId').value;
            const response = await callApi('POST', `/api/scenes/${sceneId}/execute`, null, true); // 需要认证
            handleApiResponse(response, 'executeSceneResponse');
        });

        // 6. 删除指定场景
        document.getElementById('deleteSceneForm').addEventListener('submit', async (e) => {
            e.preventDefault();
            const sceneId = document.getElementById('deleteScene_sceneId').value;
            const response = await callApi('DELETE', `/api/scenes/${sceneId}`, null, true); // 需要认证
            handleApiResponse(response, 'deleteSceneResponse');
        });


        // 初始化时更新 Token 显示
        document.addEventListener('DOMContentLoaded', updateTokenDisplay);
    </script>
</body>
</html>
